/********************************************************************************************************
 * @file OtaSettingActivity.java
 *
 * @brief for TLSR chips
 *
 * @author telink
 * @date Sep. 30, 2019
 *
 * @par Copyright (c) 2019, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
 *
 *          Licensed under the Apache License, Version 2.0 (the "License");
 *          you may not use this file except in compliance with the License.
 *          You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 *          Unless required by applicable law or agreed to in writing, software
 *          distributed under the License is distributed on an "AS IS" BASIS,
 *          WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *          See the License for the specific language governing permissions and
 *          limitations under the License.
 *******************************************************************************************************/
package com.telink.lt.ui;

import android.app.Activity;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.MenuItem;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;

import com.telink.lt.OtaSettingService;
import com.telink.lt.R;
import com.telink.lt.TelinkLog;
import com.telink.lt.ui.file.FileSelectActivity;
import com.telink.ota.foundation.OtaProtocol;
import com.telink.ota.foundation.OtaSetting;
import com.telink.ota.util.Arrays;

import java.util.List;

public class OtaSettingActivity extends BaseActivity implements View.OnClickListener {
    private final static int REQUEST_CODE_SELECT_OTA_BIN = 1;

    private final static int REQUEST_CODE_SELECT_DESCRIPTOR = 2;

    private RadioButton rb_legacy, rb_extend;

    private SeekBar sb_speed;
    private EditText et_len, et_version, et_fw_index;
    private CheckBox cb_ver_comp, cb_send_version, cb_send_fw_index, cb_secure_boot, cb_bootloader;
    private TextView tv_service, tv_char, tv_speed_desc, tv_desc, tv_select_descriptor;
    private TextView tv_select_file;
    private LinearLayout ll_extend_config, ll_fw_index_input, ll_desc;

    private List<BluetoothGattService> services;

    private BluetoothGattService selectedService;

    private BluetoothGattCharacteristic selectedCharacteristic;

    private String selectedBinPath, selectedDescriptorPath;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_ota_setting);

        services = getIntent().getParcelableArrayListExtra("services");
        setTitle("OTA Settings");
        enableBackNav(true);
        initView();

        setData(OtaSettingService.getInstance().get());
    }


    @Override
    protected void onResume() {
        super.onResume();
    }

    private void initTitle() {
        Toolbar toolbar = findViewById(R.id.title_bar);
        toolbar.inflateMenu(R.menu.menu_ota_settings);
        toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                if (item.getItemId() == R.id.item_setting_reset) {
                    resetSettings();
                }
                return false;
            }
        });
    }


    private void initView() {

        initTitle();

        findViewById(R.id.btn_save).setOnClickListener(this);

        tv_speed_desc = findViewById(R.id.tv_speed_desc);
        sb_speed = findViewById(R.id.sb_speed);
        tv_select_file = findViewById(R.id.tv_select_file);
        tv_select_file.setOnClickListener(this);
        sb_speed.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                tv_speed_desc.setText(getString(R.string.speed_desc, progress));
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });
        tv_service = findViewById(R.id.tv_service);
        tv_char = findViewById(R.id.tv_characteristic);

        tv_service.setOnClickListener(this);
        tv_char.setOnClickListener(this);

        ll_fw_index_input = findViewById(R.id.ll_fw_index_input);
        ll_extend_config = findViewById(R.id.ll_extend_config);

        rb_legacy = findViewById(R.id.rb_legacy);

        rb_extend = findViewById(R.id.rb_extend);

        rb_legacy.setOnCheckedChangeListener(PROTOCOL_CHANGE_LISTENER);
        rb_extend.setOnCheckedChangeListener(PROTOCOL_CHANGE_LISTENER);
        et_len = findViewById(R.id.et_len);
        et_version = findViewById(R.id.et_version);
        cb_ver_comp = findViewById(R.id.cb_ver_comp);
        cb_send_version = findViewById(R.id.cb_send_version);
        cb_send_fw_index = findViewById(R.id.cb_send_fw_index);
        et_fw_index = findViewById(R.id.et_fw_index);

        cb_secure_boot = findViewById(R.id.cb_secure_boot);
        cb_secure_boot.setOnCheckedChangeListener(SECURE_BOOT_CHANGE_LISTENER);
        cb_bootloader = findViewById(R.id.cb_bootloader);

        ll_desc = findViewById(R.id.ll_desc);
        tv_select_descriptor = findViewById(R.id.tv_select_descriptor);
        tv_select_descriptor.setOnClickListener(this);

    }

    private void setData(OtaSetting otaSetting) {

        int readInterval = otaSetting.readInterval;
        sb_speed.setProgress(readInterval);
        tv_speed_desc.setText(getString(R.string.speed_desc, readInterval));
        if (otaSetting.serviceUUID != null) {
            tv_service.setText(otaSetting.serviceUUID.toString());
        }

        if (otaSetting.characteristicUUID != null) {
            tv_char.setText(otaSetting.characteristicUUID.toString());
        }

        selectedBinPath = otaSetting.firmwarePath;
        tv_select_file.setText(selectedBinPath == null ? "[NULL]" : selectedBinPath);

        // secure boot and descriptor bin path
        cb_secure_boot.setChecked(otaSetting.secureBootEnable);
        selectedDescriptorPath = otaSetting.descriptorPath;
        tv_select_descriptor.setText(selectedDescriptorPath == null ? "[NULL]" : selectedDescriptorPath);


        cb_send_version.setChecked(otaSetting.sendOTAVersion);

        // firmware index
        cb_send_fw_index.setOnCheckedChangeListener(FW_INDEX_CHANGE_LISTENER);
        cb_send_fw_index.setChecked(otaSetting.sendFwIndex);


        // bootloader
        cb_bootloader.setChecked(otaSetting.bootloaderModeEnable);


        ll_fw_index_input.setVisibility(otaSetting.sendFwIndex ? View.VISIBLE : View.GONE);
        if (otaSetting.sendFwIndex) {
            et_fw_index.setText(String.format("%02X", otaSetting.fwIndex & 0xFF));
        }

        boolean isLegacyMode = otaSetting.protocol == OtaProtocol.Legacy;
        if (isLegacyMode) {
            rb_legacy.setChecked(true);
            ll_extend_config.setVisibility(View.GONE);
        } else {
            rb_extend.setChecked(true);
            ll_extend_config.setVisibility(View.VISIBLE);
            cb_ver_comp.setChecked(otaSetting.versionCompare);
            et_len.setText("" + otaSetting.pduLength);
            et_version.setText(Arrays.bytesToHexString(otaSetting.firmwareVersion, ""));
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.tv_select_file:

                startActivityForResult(new Intent(this, DownLoadActivity.class), REQUEST_CODE_SELECT_OTA_BIN);
                break;

            case R.id.tv_select_descriptor:
//                startActivityForResult(new Intent(this, FileSelectActivity.class), REQUEST_CODE_SELECT_DESCRIPTOR);
                break;

            case R.id.tv_service:
                showServicesDialog();
                break;

            case R.id.tv_characteristic:
                showCharsDialog();
                break;

            case R.id.btn_save:
                saveSettings();
                break;


        }
    }

    private void showServicesDialog() {
        if (services == null) {
            toastMsg("device not connected");
            return;
        }
        final String[] items = new String[services.size()];
        for (int i = 0; i < services.size(); i++) {
            items[i] = services.get(i).getUuid().toString();
        }
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Select Custom Service");
        builder.setItems(items, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (!services.get(which).equals(selectedService)) {
                    selectedCharacteristic = null;
                    selectedService = services.get(which);
                    tv_char.setText("not selected");
                    tv_service.setText(items[which]);
                    dialog.dismiss();
                }
            }
        });
        builder.show();

    }

    private void showCharsDialog() {
        if (selectedService == null) {
            toastMsg("select service first");
            return;
        }
        final List<BluetoothGattCharacteristic> characteristics = selectedService.getCharacteristics();
        final String[] items = new String[characteristics.size()];
        for (int i = 0; i < characteristics.size(); i++) {
            items[i] = characteristics.get(i).getUuid().toString();
        }
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Select Custom Characteristic");
        builder.setItems(items, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                selectedCharacteristic = characteristics.get(which);
                tv_char.setText(items[which]);
                dialog.dismiss();
            }
        });
        builder.show();
    }

    @Override
    public void onBackPressed() {
        OtaSetting localSetting = OtaSettingService.getInstance().get();
        OtaSetting inputSetting = getInputSetting(false);
        String errorMsg = null;
        if (inputSetting == null) {
            errorMsg = "Setting info is not complete, confirm to exit without save?";
        } else if (!localSetting.equals(inputSetting)) {
            errorMsg = "Setting info has been modified, confirm to exit without save?";
        }
        if (errorMsg != null) {
            showConfirmDialog(errorMsg, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    finish();
                }
            });
        } else {
            super.onBackPressed();
        }
    }

    // set current settings to default
    private void resetSettings() {
        toastMsg("reset setting");
        setData(new OtaSetting());
    }


    private OtaSetting getInputSetting(boolean toastError) {
        if (selectedBinPath == null) {
            if (toastError)
                toastMsg("please select bin !");
            return null;
        }


        if (cb_secure_boot.isChecked()) {
            if (selectedDescriptorPath == null) {
                toastMsg("please select descriptor bin !");
                return null;
            }
        }

        int pduLen = 16;
        byte[] versionArr = null;
        OtaProtocol selectedProtocol = rb_extend.isChecked() ? OtaProtocol.Extend : OtaProtocol.Legacy;
        if (selectedProtocol == OtaProtocol.Extend) {
            // check pdu length

            String lenInput = et_len.getText().toString().trim();
            if (TextUtils.isEmpty(lenInput)) {
                if (toastError)
                    toastMsg("input pdu length !");
                return null;
            } else {
                pduLen = Integer.parseInt(lenInput);
                if (pduLen < 16 || pduLen > 240 || pduLen % 16 != 0) {
                    if (toastError)
                        toastMsg("input pdu input error !");
                    return null;
                }
            }

            String versionInput = et_version.getText().toString().trim();

            if (TextUtils.isEmpty(versionInput)) {
                if (toastError)
                    toastMsg("input version !");
                return null;
            }
            if (versionInput.length() != 4) {
                if (toastError)
                    toastMsg("version length error !");
                return null;
            }
            versionArr = Arrays.hexToBytes(versionInput);
        }

        byte fwIndex = 0;
        if (cb_send_fw_index.isChecked()) {
            String fwIndexInput = et_fw_index.getText().toString().trim();
            if (TextUtils.isEmpty(fwIndexInput)) {
                if (toastError)
                    toastMsg("input firmware index !");
                return null;
            }

            fwIndex = Byte.parseByte(fwIndexInput, 16);
        }


        OtaSetting otaSetting = new OtaSetting();
        otaSetting.pduLength = pduLen;
        otaSetting.firmwareVersion = versionArr;
        otaSetting.versionCompare = cb_ver_comp.isChecked();
        otaSetting.sendOTAVersion = cb_send_version.isChecked();
        otaSetting.sendFwIndex = cb_send_fw_index.isChecked();
        otaSetting.bootloaderModeEnable = cb_bootloader.isChecked();
        if (otaSetting.sendFwIndex) {
            otaSetting.fwIndex = fwIndex;
        }
        if (selectedService != null) {
            otaSetting.serviceUUID = selectedService.getUuid();
        }
        if (selectedCharacteristic != null) {
            otaSetting.characteristicUUID = selectedCharacteristic.getUuid();
        }
        otaSetting.protocol = selectedProtocol;
        otaSetting.firmwarePath = selectedBinPath;

        otaSetting.readInterval = sb_speed.getProgress();
        otaSetting.versionCompare = cb_ver_comp.isChecked();

        otaSetting.secureBootEnable = cb_secure_boot.isChecked();
        if (otaSetting.secureBootEnable) {
            otaSetting.descriptorPath = selectedDescriptorPath;
        }

        return otaSetting;
    }

    private void saveSettings() {
        OtaSetting inputSetting = getInputSetting(true);
        if (inputSetting != null) {
            OtaSettingService.getInstance().updateSettings(this, inputSetting);
            setResult(RESULT_OK);
            Toast.makeText(getApplicationContext(), "save success", Toast.LENGTH_SHORT).show();
            finish();
        }
    }


    /**
     * change OTA protocol
     */
    private final CompoundButton.OnCheckedChangeListener PROTOCOL_CHANGE_LISTENER = new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            boolean isExtendChecked = rb_extend.isChecked();
            ll_extend_config.setVisibility(isExtendChecked ? View.VISIBLE : View.GONE);
        }
    };

    private final CompoundButton.OnCheckedChangeListener FW_INDEX_CHANGE_LISTENER = new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            boolean isFwIndexSelected = cb_send_fw_index.isChecked();
            ll_fw_index_input.setVisibility(isFwIndexSelected ? View.VISIBLE : View.GONE);
        }
    };

    private final CompoundButton.OnCheckedChangeListener SECURE_BOOT_CHANGE_LISTENER = new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            boolean selected = cb_secure_boot.isChecked();
            ll_desc.setVisibility(selected ? View.VISIBLE : View.GONE);
        }
    };

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode != Activity.RESULT_OK)
            return;
        if (requestCode == REQUEST_CODE_SELECT_OTA_BIN) {
            selectedBinPath = data.getStringExtra(FileSelectActivity.KEY_RESULT);
            tv_select_file.setText(selectedBinPath);
            TelinkLog.d(selectedBinPath);
        } else if (requestCode == REQUEST_CODE_SELECT_DESCRIPTOR) {
            selectedDescriptorPath = data.getStringExtra(FileSelectActivity.KEY_RESULT);
            tv_select_descriptor.setText(selectedDescriptorPath);
            TelinkLog.d(selectedDescriptorPath);
        }
    }

}
